1   /*
2    * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.crypto.provider;
27  
28  import java.util.Arrays;
29  
30  import java.security.*;
31  import java.security.spec.AlgorithmParameterSpec;
32  
33  import javax.crypto.*;
34  import javax.crypto.spec.SecretKeySpec;
35  
36  import sun.security.internal.spec.TlsPrfParameterSpec;
37  
38  /**
39   * KeyGenerator implementation for the TLS PRF function.
40   * <p>
41   * This class duplicates the HMAC functionality (RFC 2104) with
42   * performance optimizations (e.g. XOR'ing keys with padding doesn't
43   * need to be redone for each HMAC operation).
44   *
45   * @author  Andreas Sterbenz
46   * @since   1.6
47   */
48  abstract class TlsPrfGenerator extends KeyGeneratorSpi {
49  
50      // magic constants and utility functions, also used by other files
51      // in this package
52  
53      private final static byte[] B0 = new byte[0];
54  
55      final static byte[] LABEL_MASTER_SECRET = // "master secret"
56          { 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 };
57  
58      final static byte[] LABEL_KEY_EXPANSION = // "key expansion"
59          { 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 };
60  
61      final static byte[] LABEL_CLIENT_WRITE_KEY = // "client write key"
62          { 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32,
63            107, 101, 121 };
64  
65      final static byte[] LABEL_SERVER_WRITE_KEY = // "server write key"
66          { 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32,
67            107, 101, 121 };
68  
69      final static byte[] LABEL_IV_BLOCK = // "IV block"
70          { 73, 86, 32, 98, 108, 111, 99, 107 };
71  
72      /*
73       * TLS HMAC "inner" and "outer" padding.  This isn't a function
74       * of the digest algorithm.
75       */
76      private static final byte[] HMAC_ipad64  = genPad((byte)0x36, 64);
77      private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128);
78      private static final byte[] HMAC_opad64  = genPad((byte)0x5c, 64);
79      private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128);
80  
81      // SSL3 magic mix constants ("A", "BB", "CCC", ...)
82      final static byte[][] SSL3_CONST = genConst();
83  
84      static byte[] genPad(byte b, int count) {
85          byte[] padding = new byte[count];
86          Arrays.fill(padding, b);
87          return padding;
88      }
89  
90      static byte[] concat(byte[] b1, byte[] b2) {
91          int n1 = b1.length;
92          int n2 = b2.length;
93          byte[] b = new byte[n1 + n2];
94          System.arraycopy(b1, 0, b, 0, n1);
95          System.arraycopy(b2, 0, b, n1, n2);
96          return b;
97      }
98  
99      private static byte[][] genConst() {
100         int n = 10;
101         byte[][] arr = new byte[n][];
102         for (int i = 0; i < n; i++) {
103             byte[] b = new byte[i + 1];
104             Arrays.fill(b, (byte)('A' + i));
105             arr[i] = b;
106         }
107         return arr;
108     }
109 
110     // PRF implementation
111 
112     private final static String MSG = "TlsPrfGenerator must be "
113         + "initialized using a TlsPrfParameterSpec";
114 
115     private TlsPrfParameterSpec spec;
116 
117     public TlsPrfGenerator() {
118     }
119 
120     protected void engineInit(SecureRandom random) {
121         throw new InvalidParameterException(MSG);
122     }
123 
124     protected void engineInit(AlgorithmParameterSpec params,
125             SecureRandom random) throws InvalidAlgorithmParameterException {
126         if (params instanceof TlsPrfParameterSpec == false) {
127             throw new InvalidAlgorithmParameterException(MSG);
128         }
129         this.spec = (TlsPrfParameterSpec)params;
130         SecretKey key = spec.getSecret();
131         if ((key != null) && ("RAW".equals(key.getFormat()) == false)) {
132             throw new InvalidAlgorithmParameterException(
133                 "Key encoding format must be RAW");
134         }
135     }
136 
137     protected void engineInit(int keysize, SecureRandom random) {
138         throw new InvalidParameterException(MSG);
139     }
140 
141     SecretKey engineGenerateKey0(boolean tls12) {
142         if (spec == null) {
143             throw new IllegalStateException(
144                 "TlsPrfGenerator must be initialized");
145         }
146         SecretKey key = spec.getSecret();
147         byte[] secret = (key == null) ? null : key.getEncoded();
148         try {
149             byte[] labelBytes = spec.getLabel().getBytes("UTF8");
150             int n = spec.getOutputLength();
151             byte[] prfBytes = (tls12 ?
152                 doTLS12PRF(secret, labelBytes, spec.getSeed(), n,
153                     spec.getPRFHashAlg(), spec.getPRFHashLength(),
154                     spec.getPRFBlockSize()) :
155                 doTLS10PRF(secret, labelBytes, spec.getSeed(), n));
156             return new SecretKeySpec(prfBytes, "TlsPrf");
157         } catch (GeneralSecurityException e) {
158             throw new ProviderException("Could not generate PRF", e);
159         } catch (java.io.UnsupportedEncodingException e) {
160             throw new ProviderException("Could not generate PRF", e);
161         }
162     }
163 
164     static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
165             byte[] seed, int outputLength,
166             String prfHash, int prfHashLength, int prfBlockSize)
167             throws NoSuchAlgorithmException, DigestException {
168         if (prfHash == null) {
169             throw new NoSuchAlgorithmException("Unspecified PRF algorithm");
170         }
171         MessageDigest prfMD = MessageDigest.getInstance(prfHash);
172         return doTLS12PRF(secret, labelBytes, seed, outputLength,
173             prfMD, prfHashLength, prfBlockSize);
174     }
175 
176     static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
177             byte[] seed, int outputLength,
178             MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize)
179             throws DigestException {
180 
181         if (secret == null) {
182             secret = B0;
183         }
184 
185         // If we have a long secret, digest it first.
186         if (secret.length > mdPRFBlockSize) {
187             secret = mdPRF.digest(secret);
188         }
189 
190         byte[] output = new byte[outputLength];
191         byte [] ipad;
192         byte [] opad;
193 
194         switch (mdPRFBlockSize) {
195         case 64:
196             ipad = HMAC_ipad64.clone();
197             opad = HMAC_opad64.clone();
198             break;
199         case 128:
200             ipad = HMAC_ipad128.clone();
201             opad = HMAC_opad128.clone();
202             break;
203         default:
204             throw new DigestException("Unexpected block size.");
205         }
206 
207         // P_HASH(Secret, label + seed)
208         expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes,
209             seed, output, ipad, opad);
210 
211         return output;
212     }
213 
214     static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
215             byte[] seed, int outputLength) throws NoSuchAlgorithmException,
216             DigestException {
217         MessageDigest md5 = MessageDigest.getInstance("MD5");
218         MessageDigest sha = MessageDigest.getInstance("SHA1");
219         return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha);
220     }
221 
222     static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
223             byte[] seed, int outputLength, MessageDigest md5,
224             MessageDigest sha) throws DigestException {
225         /*
226          * Split the secret into two halves S1 and S2 of same length.
227          * S1 is taken from the first half of the secret, S2 from the
228          * second half.
229          * Their length is created by rounding up the length of the
230          * overall secret divided by two; thus, if the original secret
231          * is an odd number of bytes long, the last byte of S1 will be
232          * the same as the first byte of S2.
233          *
234          * Note: Instead of creating S1 and S2, we determine the offset into
235          * the overall secret where S2 starts.
236          */
237 
238         if (secret == null) {
239             secret = B0;
240         }
241         int off = secret.length >> 1;
242         int seclen = off + (secret.length & 1);
243 
244         byte[] output = new byte[outputLength];
245 
246         // P_MD5(S1, label + seed)
247         expand(md5, 16, secret, 0, seclen, labelBytes, seed, output,
248             HMAC_ipad64.clone(), HMAC_opad64.clone());
249 
250         // P_SHA-1(S2, label + seed)
251         expand(sha, 20, secret, off, seclen, labelBytes, seed, output,
252             HMAC_ipad64.clone(), HMAC_opad64.clone());
253 
254         return output;
255     }
256 
257     /*
258      * @param digest the MessageDigest to produce the HMAC
259      * @param hmacSize the HMAC size
260      * @param secret the secret
261      * @param secOff the offset into the secret
262      * @param secLen the secret length
263      * @param label the label
264      * @param seed the seed
265      * @param output the output array
266      */
267     private static void expand(MessageDigest digest, int hmacSize,
268             byte[] secret, int secOff, int secLen, byte[] label, byte[] seed,
269             byte[] output, byte[] pad1, byte[] pad2) throws DigestException {
270         /*
271          * modify the padding used, by XORing the key into our copy of that
272          * padding.  That's to avoid doing that for each HMAC computation.
273          */
274         for (int i = 0; i < secLen; i++) {
275             pad1[i] ^= secret[i + secOff];
276             pad2[i] ^= secret[i + secOff];
277         }
278 
279         byte[] tmp = new byte[hmacSize];
280         byte[] aBytes = null;
281 
282         /*
283          * compute:
284          *
285          *     P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
286          *                            HMAC_hash(secret, A(2) + seed) +
287          *                            HMAC_hash(secret, A(3) + seed) + ...
288          * A() is defined as:
289          *
290          *     A(0) = seed
291          *     A(i) = HMAC_hash(secret, A(i-1))
292          */
293         int remaining = output.length;
294         int ofs = 0;
295         while (remaining > 0) {
296             /*
297              * compute A() ...
298              */
299             // inner digest
300             digest.update(pad1);
301             if (aBytes == null) {
302                 digest.update(label);
303                 digest.update(seed);
304             } else {
305                 digest.update(aBytes);
306             }
307             digest.digest(tmp, 0, hmacSize);
308 
309             // outer digest
310             digest.update(pad2);
311             digest.update(tmp);
312             if (aBytes == null) {
313                 aBytes = new byte[hmacSize];
314             }
315             digest.digest(aBytes, 0, hmacSize);
316 
317             /*
318              * compute HMAC_hash() ...
319              */
320             // inner digest
321             digest.update(pad1);
322             digest.update(aBytes);
323             digest.update(label);
324             digest.update(seed);
325             digest.digest(tmp, 0, hmacSize);
326 
327             // outer digest
328             digest.update(pad2);
329             digest.update(tmp);
330             digest.digest(tmp, 0, hmacSize);
331 
332             int k = Math.min(hmacSize, remaining);
333             for (int i = 0; i < k; i++) {
334                 output[ofs++] ^= tmp[i];
335             }
336             remaining -= k;
337         }
338     }
339 
340     /**
341      * A KeyGenerator implementation that supports TLS 1.2.
342      * <p>
343      * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF
344      * calculations.  As of 2010, there is no PKCS11-level support for TLS
345      * 1.2 PRF calculations, and no known OS's have an internal variant
346      * we could use.  Therefore for TLS 1.2, we are updating JSSE to request
347      * a different provider algorithm:  "SunTls12Prf".  If we reused the
348      * name "SunTlsPrf", the PKCS11 provider would need be updated to
349      * fail correctly when presented with the wrong version number
350      * (via Provider.Service.supportsParameters()), and add the
351      * appropriate supportsParamters() checks into KeyGenerators (not
352      * currently there).
353      */
354     static public class V12 extends TlsPrfGenerator {
355         protected SecretKey engineGenerateKey() {
356             return engineGenerateKey0(true);
357         }
358     }
359 
360     /**
361      * A KeyGenerator implementation that supports TLS 1.0/1.1.
362      */
363     static public class V10 extends TlsPrfGenerator {
364         protected SecretKey engineGenerateKey() {
365             return engineGenerateKey0(false);
366         }
367     }
368 }